<?php

namespace App\Controllers;

use App\Helpers\CommonUtil;
use CodeIgniter\HTTP\Files\UploadedFile;
use Exception;
use App\Helpers\NewsHelper;

class News extends BaseController
{
    private static array $rules = [
        "title"   => 'required|regex_match[/^.{2,200}$/]',
        "summary" => 'if_exist|string',
        "url"     => 'if_exist|valid_url_strict',
        "cover"   => 'if_exist|is_image|max_size[cover,10240]',
    ];

    private static array $errorsMsg = [
        'title'   => [
            'required'    => '文章标题不能为空',
            'regex_match' => '标题长度为 2 至 200 个字符',
        ],
        'summary' => [
            'string' => ''
        ],
        'url'     => [
            'valid_url_strict' => '请输入有效的 URL'
        ],
        'cover'   => [
            'is_image' => '请上传图片文件',
            'max_size' => '文件不能超过 10M',
        ],
    ];

    public function index(): \CodeIgniter\HTTP\ResponseInterface
    {
        $rules     = [
            "page"      => 'if_exist|is_natural_no_zero',
            "pageSize"  => 'if_exist|less_than_equal_to[50]',
            "title"     => 'if_exist|string',
            "userId"    => 'if_exist|is_not_unique[user.id]',
            "isPublish" => 'if_exist|string',
            "isDelete"  => 'if_exist|string',
            "orderBy"   => 'if_exist|in_list[id,title,publish_time]',
        ];
        $errorsMsg = [
            'page'     => [
                'is_natural_no_zero' => '当前页数不能小于1',
            ],
            'pageSize' => [
                'less_than_equal_to' => '分页条数必须少于50',
            ],
            'userId'   => [
                'is_not_unique' => '当前用户ID不存在'
            ],
            'orderBy'  => [
                'in_list' => '排序类型只能是 id,title,publish_time,create_time 中的一个'
            ]
        ];

        try {
            $this->getUser();

            if (!$this->validate($rules, $errorsMsg)) {
                $errors = $this->validator->getErrors();

                throw new Exception(array_shift($errors));
            }

            $query    = $this->validator->getValidated();
            $page     = intval($query["page"] ?? 1);
            $pageSize = intval($query["pageSize"] ?? 10);
        } catch (Exception $e) {
            return $this->responseMsg($e->getMessage());
        }

        $builder = db_connect()->table("news")->select("news.id, title, summary, avatar, user_id, user.username, url, publish_time, news.create_time, modify_time, news.delete_time")
            ->join("user", "user.id = news.user_id");

        if (!empty($query["title"])) {
            $builder->like("title", $query["title"]);
        }

        if (!empty($query["userId"])) {
            $builder->where("user_id", intval($query["userId"]));
        }

        if (isset($query["isPublish"])) {
            $builder->where($query["isPublish"] ? "publish_time is not null" : "publish_time is null");
        }

        if (isset($query["isDelete"])) {
            $builder->where($query["isDelete"] ? "news.delete_time is not null" : "news.delete_time is null");
        }

        if (!empty($query["orderBy"])) {
            $builder->orderBy($query["orderBy"], "DESC");
        } else {
            $builder->orderBy("news.create_time", "DESC");
        }

        $countBuilder = clone $builder;
        $count        = $countBuilder->get()->getNumRows();
        $list         = $builder->get($pageSize, ($page - 1) * $pageSize);

        return $this->responseJson([
            "list"  => $list->getResultObject(),
            "total" => ceil($count / $pageSize),
            "count" => $count,
        ]);
    }

    public function create(): \CodeIgniter\HTTP\ResponseInterface
    {
        try {
            $user = $this->getUser();

            if (!$this->validate(self::$rules, self::$errorsMsg)) {
                $errors = $this->validator->getErrors();

                throw new Exception(array_shift($errors));
            }

            $post  = $this->validator->getValidated();
            $cover = $this->request->getFile('cover');

            (new NewsHelper())->create($user->id, $post['title'], $post['summary'] ?? '', $post['url'] ?? '', $cover);
        } catch (Exception $e) {
            return $this->responseMsg($e->getMessage());
        }

        return $this->responseMsg();
    }

    public function modify(int $id): \CodeIgniter\HTTP\ResponseInterface
    {
        try {
            $user = $this->getUser();

            if (!$this->validate(self::$rules, self::$errorsMsg)) {
                $errors = $this->validator->getErrors();

                throw new Exception(array_shift($errors));
            }

            $post  = $this->validator->getValidated();
            $cover = $this->request->getFile('cover');

            (new NewsHelper())->modify($user->id, $id, $post['title'], $post['summary'] ?? '', $post['url'] ?? '', $cover);
        } catch (Exception $e) {
            return $this->responseMsg($e->getMessage());
        }

        return $this->responseMsg();
    }

    public function detail(int $id): \CodeIgniter\HTTP\ResponseInterface
    {
        try {
            $news = db_connect()->table("news")->where("id", $id)->get()->getRow();
        } catch (Exception $e) {
            return $this->responseMsg($e->getMessage());
        }

        return $this->responseJson($news);
    }

    public function publish(int $id): \CodeIgniter\HTTP\ResponseInterface
    {
        try {
            $user = $this->getUser();

            $validation  = \Config\Services::validation();
            $post        = $this->request->getPost();
            $publishTime = $post["time"] ?? date("Y-m-d H:i:s");

            if (!$validation->check($publishTime, 'required|valid_date[Y-m-d H:i:s]')) {
                $errors = $validation->getErrors();

                throw new \Exception(array_shift($errors));
            }

            (new NewsHelper())->publish($user->id, $id);
        } catch (Exception $e) {
            return $this->responseMsg($e->getMessage());
        }

        return $this->responseMsg();
    }

    public function recall(int $id): \CodeIgniter\HTTP\ResponseInterface
    {
        try {
            $user = $this->getUser();

            (new NewsHelper())->recall($user->id, $id);
        } catch (Exception $e) {
            return $this->responseMsg($e->getMessage());
        }

        return $this->responseMsg();
    }

    public function delete(int $id): \CodeIgniter\HTTP\ResponseInterface
    {
        try {
            $user = $this->getUser();
            (new NewsHelper())->delete($user->id, $id);
        } catch (Exception $e) {
            return $this->responseMsg($e->getMessage());
        }

        return $this->responseMsg();
    }

    public function recovery(int $id): \CodeIgniter\HTTP\ResponseInterface
    {
        try {
            $user = $this->getUser();
            (new NewsHelper())->recovery($user->id, $id);
        } catch (Exception $e) {
            return $this->responseMsg($e->getMessage());
        }

        return $this->responseMsg();
    }

    public function batch(): \CodeIgniter\HTTP\ResponseInterface
    {
        $conn = db_connect();

        try {
            $user = $this->getUser();

            $batchRule = [
                'ids' => 'required',
                'opt' => 'required|in_list[publish,recall,delete,recovery]'
            ];
            $errorsMsg = [
                'ids' => [
                    'required' => '文章 ID 用逗号分隔',
                ],
                'opt' => [
                    'required' => '请填写操作类型',
                    'in_list'  => '必须是 publish,recall,delete,recovery 中的一个'
                ]
            ];

            if (!$this->validate($batchRule, $errorsMsg)) {
                $errors = $this->validator->getErrors();

                throw new Exception(array_shift($errors));
            }

            $post = $this->validator->getValidated();
            $ids  = $post["ids"] ?? NULL;
            $opt  = $post["opt"] ?? NULL;

            $ids = array_filter(array_unique(explode(',', $ids)));

            $conn->transBegin();
            $query = $conn->table("news")->whereIn('id', $ids)->where('user_id', $user->id);

            switch ($opt) {
                case 'publish':
                    $query->where('delete_time is null');
                    $data = ['publish_time' => date('Y-m-d H:i')];
                    break;
                case 'recall':
                    $query->where('delete_time is null');
                    $data = ['publish_time' => NULL];
                    break;
                case 'delete':
                    $data = ['publish_time' => NULL, 'delete_time' => date('Y-m-d H:i')];
                    break;
                case 'recovery':
                    $data = ['publish_time' => NULL, 'delete_time' => NULL];
                    break;
                default:
                    throw new Exception("操作命令错误");
            }

            $query->update($data);
            $cnt  = count($ids);
            $rows = $conn->affectedRows();

            if ($cnt != $rows) {
                throw new Exception("批处理操作行数与影响行数不匹配，ids({$cnt}):rows({$rows})");
            }

            $conn->transCommit();
        } catch (Exception $e) {
            $conn->transRollback();
            return $this->responseMsg($e->getMessage());
        }

        return $this->responseMsg();
    }

    public function users(): \CodeIgniter\HTTP\ResponseInterface
    {
        try {
            log_message('error', 'Some variable did not contain a value.');
            $res = db_connect()->table('user')->select('id, username')->get()->getResultObject();

            return $this->responseJson(['list' => $res]);
        } catch (Exception $e) {
            return $this->responseMsg($e->getMessage());
        }
    }

    /**
     * @throws Exception
     */
    public function upload(): \CodeIgniter\HTTP\ResponseInterface
    {
        $path = "";
        $file = $this->request->getFile('file');

        if ($file instanceof UploadedFile) {
            $path = CommonUtil::getUploadFilePath($file, 'other');
        }

        return $this->responseJson(['file' => $path]);
    }
}
